/**********************************************************************************************************************
 * @file    public.h
 * @author  Queclink Hubert.Lee
 * @date    2016-10-14
 * @brief   应用程序辅助开发库公共定义, 和公共函数声明
 * @ingroup aadl
 *
 * Copyright (C) 2016 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @attention
 *
 * @usage
 * 1. struct aadl_ops *aadl
 *   @brief  系统提供给库的公共函数的指针;
 * 2. void aadl_delay_ms(unsigned int ms)
 *   @brief  毫秒级延时函数;
 *   @note   优先使用切换线程的方式实现延时;
 *   @param  ms: [I], 待延时时间, 单位ms;
 * 3. void aadl_delay_ms_here(unsigned int ms)
 *   @brief  毫秒级延时函数;
 *   @note   不(主动)切换线程的延时;
 *   @param  ms: [I], 待延时时间, 单位ms;
 * 4. void aadl_abdicate_resource_one_jiffy(void)
 *   @brief  AADL退出占用CPU一会儿(用于适配OS环境);
 * 5. bool aadl_is_timeout(unsigned int start_time, unsigned int timeout)
 *   @brief  判断是否超时;
 *   @param  start_time: [I], 起始时间, 单位ms;
 *           timeout: [I], 超时时间, 单位ms;
 *   @retval true:已超时, false:未超时
 * 6. void aadl_watchdog_feed(void)
 *   @brief  看门狗喂狗函数
 *   @note   包含判定看门狗是否打开操作
 * 7. int aadl_id_allocate(struct list_head *head, size_t type_size)
 *   @brief  申请一个ID号(申请到的ID在一个链表中是唯一的);
 *   @note   申请的ID号是应用于链表的, 且要求该链表结构体的首元素是ID号, 末元素是 struct list_head 变量;
 *   @param  head: [I], 链表头部指针;
 *           type_size: [I], 链表结构体长度;
 *   @retval 非负数:申请到的ID号, others:错误码
 * 8. int aadl_id_allocate_union(struct list_head *head1, size_t type1_size, struct list_head *head2, size_t type2_size)
 *   @brief  申请一个ID号(申请到的ID在两个链表中都是唯一的);
 *   @note   申请的ID号是应用于链表的, 且要求两个链表结构体的首元素都是ID号, 末元素都是 struct list_head 变量;
 *   @param  head1: [I], 链表1头部指针;
 *           type1_size: [I], 链表1结构体长度;
 *           head2: [I], 链表2头部指针;
 *           type2_size: [I], 链表2结构体长度
 *   @retval 非负数:申请到的ID号, others:错误码
 *
 *********************************************************************************************************************/


#ifndef __AADL_PUBLIC_H
#define __AADL_PUBLIC_H

/* includes ---------------------------------------------------------------------------------------------------------*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <public/errno.h>
#include <aadl/aadl.h>

#ifdef __cplusplus
extern "C" {
#endif


#define ARRAY_COUNT(array)              (sizeof(array) / sizeof(array[0]))

#define set_bit(word, bit)              (word) |= (1ul << (bit))
#define clr_bit(word, bit)              (word) &= ~(1ul << (bit))
#define get_bit_status(word, bit)       ((0 != ((word) & (1ul << (bit)))) ? 1 : 0)

#define array_element_address_get(array, element, value) \
    do { \
        int i; \
        for (i=0; i < ARRAY_COUNT(array); i++) { \
            if (value == array[i].element) \
                return &array[i]; \
        } \
        return NULL; \
    } while(0)

typedef int level_t;    /* 电平状态, 0/1 */

/* 由结构体类型(type)的成员(member)的指针(member_ptr)计算结构体的基地址 */
#define type_entry(type, member, member_ptr)    ((type *)((char *)member_ptr - ((size_t) &((type *)0)->member)))

/* 由结构体中的 struct list_head 变量指针(pos)和结构体长度计算结构体的基地址,
 * 要求 struct list_head 变量是结构体最后一个元素 */
#define _list_entry(pos, type_size)             ((char *)pos + sizeof(struct list_head) - type_size)

#define is_null_string(str)                     ('\0' == *(char *)(str))

/* Line Feed, 换行, \r\n or \n */
#define is_line_feed_char(ch)                   (('\r' == (ch)) || ('\n' == (ch)))

#define AADL_INVALID_ID         (-1)

#define AADL_TIMING_NOTYET      0

#include "public/weak.h"
#define aadl_malloc(size) lib_malloc(size)
#define aadl_free(ptr)    lib_free(ptr)

#define OBJECT_MSG(obj, msg)    msg

extern struct aadl_ops * const aadl;

/* log channel setting */

int aadl_debug_set(int id, char *loglevel);
void aadl_watchdog_feed(void);
void aadl_delay_ms(unsigned int ms);
void aadl_delay_ms_here(unsigned int ms);
void aadl_abdicate_resource_one_jiffy(void);
bool aadl_is_timeout(unsigned int start_time, unsigned int timeout);
int quec_string_split(char *str, size_t len, const char *delim, int *argc, char **argv);
/**
 * @brief 检测数组是否为0
 * 
 * @param array 
 * @param n 
 * @return int 1:全为0 | 0：不全为0
 */
int is_array_zero(uint8_t *array, int n);

#ifdef __cplusplus
}
#endif

#endif /* __AADL_PUBLIC_H */
